home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / rpg / crossfir.92 / crossfir / crossfire-0.92.5 / common / living.c < prev    next >
C/C++ Source or Header  |  1996-07-24  |  47KB  |  1,455 lines

  1. /*
  2.  * static char *rcsid_living_c =
  3.  *   "$Id: living.c,v 1.36 1996/07/24 07:02:43 master Exp master $";
  4.  */
  5.  
  6. /*
  7.     CrossFire, A Multiplayer game for X-windows
  8.  
  9.     Copyright (C) 1992 Frank Tore Johansen
  10.  
  11.     This program is free software; you can redistribute it and/or modify
  12.     it under the terms of the GNU General Public License as published by
  13.     the Free Software Foundation; either version 2 of the License, or
  14.     (at your option) any later version.
  15.  
  16.     This program is distributed in the hope that it will be useful,
  17.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.     GNU General Public License for more details.
  20.  
  21.     You should have received a copy of the GNU General Public License
  22.     along with this program; if not, write to the Free Software
  23.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  
  25.     The author can be reached via e-mail to frankj@ifi.uio.no.
  26. */
  27.  
  28. #include <global.h>
  29. #include <living.h>
  30. #include <funcpoint.h>
  31.  
  32.  
  33. static int con_bonus[MAX_STAT + 1]={
  34.   -6,-5,-4,-3,-2,-1,-1,0,0,0,0,1,2,3,4,5,6,7,8,9,10,12,14,16,18,20,
  35.   22,25,30,40,50
  36. };
  37. /* changed the name of this to "sp_bonus" from "int_bonus" 
  38.  * because Pow can now be the stat that controls spellpoint
  39.  * advancement. -b.t.
  40.  */
  41. static int sp_bonus[MAX_STAT + 1]={
  42.   -10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,12,15,20,25,
  43.   30,40,50,70,100
  44. };
  45.  
  46. static int grace_bonus[MAX_STAT +1] = {
  47.     -10,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,12,15,20,25,
  48.   30,40,50,70,100
  49. };
  50.  
  51. /* At around a 59 bonus, under the present system, it possible to make
  52.  * money by buying an item then selling it.  I smoothed out the
  53.  * increments some, making the gains more linear.  Before, in some cases,
  54.  * the gain of a point might increase the bonus by 4, but the next point
  55.  * gained only increased it by 2.  Now, for almost all positive bonuses,
  56.  * it is increased by 3 per point.
  57.  * Cost of buying an item is (6*(100-cha_bonus))/100
  58.  * Cost of selling an item is 100/(100-cha_bonus)
  59.  * This, it costs (60000-1200cha_bonus+6*cha_bonus^2)/10000 to buy something
  60.  * than to sell something.
  61.  * Various numbers of interest:
  62.  * bonus    buy/sell value    cha to have that bonus
  63.  * -100        24
  64.  * -83        20.09         (0)
  65.  * -59        15.17         (2)
  66.  * -29        9.98         (5)
  67.  *   0        6.00        (12)
  68.  *   8        5.08        (14)
  69.  *  18        4.03        (18)
  70.  *  29        3.02        (21)
  71.  *  42        2.02        (26)
  72.  *  59        1.009        (30+)
  73.  *
  74.  * What this shows is that a penalty is very harsh, and actual benefit
  75.  * is of a diminishing nature.  Thus, I changed the cha_bonus so that
  76.  * penalties are no longer so bad - a player should never have to pay more
  77.  * than about 10 times to buy an item than what he gets for selling it.
  78.  */
  79. #if 0    /* old bonus */
  80. int cha_bonus[MAX_STAT + 1]={
  81.   -80,-70,-60,-50,-40,-30,-25,-20,-15,-10,-7,-3,0,4,7,10,13,16,19,22,25,28,31,
  82.    34,37,40,43,46,49,52,55
  83. };
  84. #endif
  85. int cha_bonus[MAX_STAT + 1]={
  86.   -35,-32,-29,-26,-23,-20,-17,-14,-11,-8,-5,-2,1,4,7,10,13,16,19,22,25,28,31,
  87.    34,37,40,43,46,49,52,55
  88. };
  89.  
  90. int dex_bonus[MAX_STAT + 1]={
  91.   -4,-3,-2,-2,-1,-1,-1,0,0,0,0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,5,5,6,6,7
  92. };
  93. static float speed_bonus[MAX_STAT + 1]={
  94.   -0.4, -0.4, -0.3, -0.3, -0.2, -0.2, -0.2, -0.1, -0.1, -0.1, -0.05, 0, 0, 0,
  95.   0.05, 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.8, 1.0, 1.2, 1.4,
  96.   1.6, 1.8, 2.0, 2.5, 3.0
  97. };
  98. int dam_bonus[MAX_STAT + 1]={
  99.   -2,-2,-2,-1,-1,-1,0,0,0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,5,5,6,6,7,8,10,15
  100. };
  101. int thaco_bonus[MAX_STAT + 1]={
  102.   -2,-2,-1,-1,0,0,0,0,0,0,0,0,0,0,1,1,1,2,2,2,3,3,3,4,4,5,5,6,7,8,10
  103. };
  104. int max_carry[MAX_STAT + 1]={
  105.   2,4,7,11,16,22,29,37,46,56,67,79,92,106,121,137,154,172,191,211,232,254,277,
  106.   301,326,352,400,450,500,600,1000
  107. };
  108. int learn_spell[MAX_STAT + 1]={
  109.   0,0,0,1,2,4,8,12,16,25,36,45,55,65,70,75,80,85,90,95,100,100,100,100,100,
  110.   100,100,100,100,100,100
  111. };
  112. int cleric_chance[MAX_STAT + 1]={
  113.   100,100,100,100,100,100,100,90,80,70,60,50,45,40,35,30,25,20,15,10,5,0,-5,-10,-15,-20,-25,-30,-35,-40,-50
  114. };
  115. int turn_bonus[MAX_STAT + 1]={
  116.   -1,-1,-1,-1,-1,-1,-1,-1,0,0,0,1,1,1,2,2,2,3,3,3,4,4,5,5,6,7,8,9,10,12,15
  117. };
  118. int fear_bonus[MAX_STAT + 1]={
  119.   3,3,3,3,2,2,2,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
  120. };
  121.  
  122. /*
  123.    Since this is nowhere defined ...
  124.    Both come in handy at least in function add_exp()
  125. */
  126.  
  127. #define MAXLEVEL      110
  128. #define MAX_EXPERIENCE  levels[MAXLEVEL]
  129.  
  130. /* because exp_obj sum to make the total score,
  131.  * we cannot allow that sum to exceed the maximum
  132.  * amount of experience a player can gain. Thus
  133.  * we define MAX_EXP_IN_OBJ. It is important to try
  134.  * to make the value of MAX_EXP_CAT close to the
  135.  * actual number of experience objects in the game,
  136.  * otherwise the maximum level in any experience
  137.  * category could be quite low. To help the situation
  138.  * out a little I added 10 more levels, and jacked
  139.  * up the last level experience value. Its out of 
  140.  * line with progression of previous levels, so 
  141.  * if more levels are desired, this should be fixed.
  142.  *  -b.t.
  143.  */
  144.  
  145. #define MAX_EXP_IN_OBJ levels[MAXLEVEL]/(MAX_EXP_CAT - 1) 
  146.  
  147. static long levels[MAXLEVEL+1]={
  148. 0,
  149. 0,1000,2000,4000, 8000,
  150. 16000,32000,64000,125000,250000,        /* 10 */
  151. 500000,900000,1400000,2000000,2600000,
  152. 3300000,4100000,4900000,5700000,6600000,    /* 20 */
  153. 7500000,8400000,9300000,10300000,11300000,
  154. 12300000,13300000,14400000,15500000,16600000,    /* 30 */
  155. 17700000,18800000,19900000,21100000,22300000,    
  156. 23500000,24700000,25900000,27100000,28300000,    /* 40 */
  157. 29500000,30800000,32100000,33400000,34700000,
  158. 36000000,37300000,38600000,39900000,41200000,    /* 50 */
  159. 42600000,44000000,45400000,46800000,48200000,
  160. 49600000,51000000,52400000,53800000,55200000,    /* 60 */
  161. 56600000,58000000,59400000,60800000,62200000,
  162. 63700000,65200000,66700000,68200000,69700000,    /* 70 */
  163. 71200000,72700000,74200000,75700000,77200000,
  164. 78700000,80200000,81700000,83200000,84700000,    /* 80 */
  165. 86200000,87700000,89300000,90900000,92500000,
  166. 94100000,95700000,97300000,98900000,100500000,    /* 90 */
  167. 102100000,103700000,105300000,106900000,108500000,
  168. 110100000,111700000,113300000,114900000,116500000,    /* 100 */
  169. 118100000,119700000,121300000,122900000,124500000,     
  170. 126100000,127700000,129300000,130900000,785400000    /* 110 */};
  171.  
  172. /* Max level is 100.  By making it 101, it means values 0->100 are valid.
  173.  * Thus, we can use op->level directly, and it also works for level 0 people.
  174.  */
  175. int savethrow[101]={
  176.   18,
  177.   18,17,16,15,14,14,13,13,12,12,12,11,11,11,11,10,10,10,10, 9,
  178.    9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6,
  179.    6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
  180.    4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2,
  181.    2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  182. };
  183.  
  184. int object_saves[NROFATTACKS][NROFMATERIALS] = {
  185.   /* Paper, Iron, Glass, Leather, Wood, Organic, Stone, Cloth, Adamant */
  186.   {15, 2,14, 5,10, 3, 2,14,0}, /* Physical */
  187.   {10,12,11,10,11,12, 5,11,0}, /* Magic */
  188.   {17, 3, 8,10,13, 9, 2,13,0}, /* Fire */
  189.   { 9,12, 3, 3, 2,11, 2, 4,0}, /* Electricity */
  190.   { 5, 2,10, 3, 2, 3, 2, 4,0}, /* Cold */
  191.   { 7,10, 5,10,10,10, 2, 5,0}, /* Water */
  192.   {13, 7, 1,10, 9, 9, 1,10,0}, /* Acid */
  193.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Drain */
  194.   {20,20,20,20,20,20,20,20,0}, /* Weaponmagic */
  195.   {15,15,15,15,15,15,15,15,0}, /* Ghosthit */
  196.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* IT */
  197.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Disease */
  198.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Paralyze */
  199.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Turn undead */
  200.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Fear */
  201.   {10,10, 0,12,12, 0, 5, 5,0}, /* Cancellation */
  202.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Depletion */
  203.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Death */
  204.   { 0, 0, 0, 0, 0, 0, 0, 0,0}, /* Chaos */
  205.   { 0, 0, 0, 0, 0, 0, 0, 0,0},  /* Counterspell */
  206.   { 0, 0, 0, 0, 0, 0, 0, 0,0}  /* Godpower */
  207. };
  208.  
  209. char *attacks[NROFATTACKS] = {
  210.   "physical", "magical", "fire", "electricity", "cold", "confusion",
  211.   "acid", "drain", "weaponmagic", "ghosthit", "poison", "slow",
  212.   "paralyze", "turn undead", "fear", "cancellation", "depletion", "death",
  213.   "chaos","counterspell","god power"
  214. };
  215.  
  216. static char *drain_msg[7] = {
  217.   "Oh no! You are weakened!",
  218.   "You're feeling clumsy!",
  219.   "You feel less healthy",
  220.   "You suddenly begin to lose your memory!",
  221.   "Your face gets distorted!",
  222.   "Watch out, your mind is going!", 
  223.   "Your spirit feels drained!"
  224. };
  225. char *restore_msg[7] = {
  226.   "You feel your strength return.",
  227.   "You feel your agility return.",
  228.   "You feel your health return.",
  229.   "You feel your wisdom return.",
  230.   "You feel your charisma return.",
  231.   "You feel your memory return.", 
  232.   "You feel your spirits return."
  233. };
  234. char *gain_msg[7] = {
  235.     "You feel stronger.",
  236.     "You feel more agile.",
  237.     "You feel healthy.",
  238.     "You feel wiser.",
  239.     "You seem to look better.",
  240.     "You feel smarter.", 
  241.     "You feel more potent."
  242. };
  243. char *lose_msg[7] = {
  244.     "You feel weaker!",
  245.     "You feel clumsy!",
  246.     "You feel less healthy!",
  247.     "You lose some of your memory!",
  248.     "You look ugly!",
  249.     "You feel stupid!", 
  250.     "You feel less potent!"
  251. };
  252.  
  253. char *statname[7] = {
  254.   "strength", "dexterity", "constitution", "wisdom", "charisma", "intelligence","power" 
  255. };
  256.  
  257. char *short_stat_name[7] = {
  258.   "Str", "Dex", "Con", "Wis", "Cha", "Int","Pow" 
  259. };
  260.  
  261.  
  262. /*
  263.  * sets Str/Dex/con/Wis/Cha/Int/Pow in stats to value, depending on
  264.  * what attr is (STR to POW).
  265.  */
  266.  
  267. void
  268. set_attr_value(living *stats,int attr,signed char value) {
  269.   switch(attr) {
  270.   case STR:
  271.     stats->Str=value;
  272.     break;
  273.   case DEX:
  274.     stats->Dex=value;
  275.     break;
  276.   case CON:
  277.     stats->Con=value;
  278.     break;
  279.   case WIS:
  280.     stats->Wis=value;
  281.     break;
  282.   case POW:
  283.     stats->Pow=value;
  284.     break;
  285.   case CHA:
  286.     stats->Cha=value;
  287.     break;
  288.   case INT:
  289.     stats->Int=value;
  290.     break;
  291.   }
  292. }
  293.  
  294. /*
  295.  * Like set_attr_value(), but instead the value (which can be negative)
  296.  * is added to the specified stat.
  297.  */
  298.  
  299. void
  300. change_attr_value(living *stats,int attr,signed char value) {
  301.   if (value==0) return;
  302.   switch(attr) {
  303.   case STR:
  304.     stats->Str+=value;
  305.     break;
  306.   case DEX:
  307.     stats->Dex+=value;
  308.     break;
  309.   case CON:
  310.     stats->Con+=value;
  311.     break;
  312.   case WIS:
  313.     stats->Wis+=value;
  314.     break;
  315.   case POW:
  316.     stats->Pow+=value;
  317.     break;
  318.   case CHA:
  319.     stats->Cha+=value;
  320.     break;
  321.   case INT:
  322.     stats->Int+=value;
  323.     break;
  324.   default:
  325.     LOG(llevError,"Invalid attribute in change_attr_value: %d\n", attr);
  326.   }
  327. }
  328.  
  329. /*
  330.  * returns the specified stat.  See also set_attr_value().
  331.  */
  332.  
  333. signed char
  334. get_attr_value(living *stats,int attr) {
  335.   switch(attr) {
  336.   case STR:
  337.     return(stats->Str);
  338.   case DEX:
  339.     return(stats->Dex);
  340.   case CON:
  341.     return(stats->Con);
  342.   case WIS:
  343.     return(stats->Wis);
  344.   case CHA:
  345.     return(stats->Cha);
  346.   case INT:
  347.     return(stats->Int);
  348.   case POW:
  349.     return(stats->Pow);
  350.   }
  351.   return 0;
  352. }
  353.  
  354. /*
  355.  * Ensures that all stats (str/dex/con/wis/cha/int) are within the
  356.  * 1-30 stat limit.
  357.  */
  358.  
  359. void check_stat_bounds(living *stats) {
  360.   int i,v;
  361.   for(i=0;i<7;i++)
  362.     if((v=get_attr_value(stats,i))>MAX_STAT)
  363.       set_attr_value(stats,i,MAX_STAT);
  364.     else if(v<MIN_STAT)
  365.       set_attr_value(stats,i,MIN_STAT);
  366. }
  367.  
  368. #define ORIG_S(xyz,abc)    (op->contr->orig_stats.abc)
  369.  
  370. /*
  371.  * Adds abilities to the first object based on what the second object
  372.  * gives to appliers.  If the second object does not have the APPLIED
  373.  * flag set, it is assumed that it is being unapplied, and any abilities
  374.  * it gives are subtracted from the first object.
  375.  * (This is of course a problem now, since several objects may give
  376.  * the same abilities, thus change_abil() is used mostly to display
  377.  * messages, while fix_player() is called afterwards.)
  378.  * Also writes a more or less informative message to the first object
  379.  * about what abilities were gained/lost.
  380.  */
  381.  
  382. int change_abil(object *op, object *tmp) {
  383.   int flag=QUERY_FLAG(tmp,FLAG_APPLIED)?1:-1,i,j;
  384.  
  385.   if(op->type==PLAYER) {
  386.     if (tmp->type==POTION) {
  387.       for(j=0;j<7;j++) {
  388.         i = get_attr_value(&(op->contr->orig_stats),j);
  389.  
  390.         if (((i+flag*get_attr_value(&(tmp->stats),j))<=
  391.         (20+tmp->stats.sp + get_attr_value(&(op->arch->clone.stats),j)))
  392.         && i>0)
  393.     {
  394.             change_attr_value(&(op->contr->orig_stats),j,
  395.                           flag*get_attr_value(&(tmp->stats),j));
  396.         tmp->stats.sp=0;/* Fix it up for super potions */
  397.     }
  398.     else {
  399.         set_attr_value(&(tmp->stats),j,0);
  400.     }
  401.       }
  402.     for(j=0;j<7;j++)
  403.       change_attr_value(&(op->stats),j,flag*get_attr_value(&(tmp->stats),j));
  404.     check_stat_bounds(&(op->stats));
  405.     }
  406.   }
  407.   if(flag==1)
  408.     op->immune|=tmp->immune,
  409.     op->protected|=tmp->protected,
  410.     op->vulnerable|=tmp->vulnerable,
  411.     op->attacktype|=tmp->attacktype,
  412.     op->path_attuned|=tmp->path_attuned,
  413.     op->path_repelled|=tmp->path_repelled,
  414.     op->path_denied|=tmp->path_denied;
  415.   else
  416.     op->immune&=~tmp->immune,
  417.     op->protected&=~tmp->protected,
  418.     op->vulnerable&=~tmp->vulnerable,
  419.     op->attacktype&=~tmp->attacktype,
  420.     op->path_attuned&=~tmp->path_attuned,
  421.     op->path_repelled&=~tmp->path_repelled,
  422.     op->path_denied&=~tmp->path_denied;
  423.   if(tmp->attacktype & AT_CONFUSION) {
  424.     if(flag>0)
  425.       (*draw_info_func)(NDI_UNIQUE, 0, op,"Your hands begin to glow red.");
  426.     else
  427.       (*draw_info_func)(NDI_UNIQUE, 0, op,"Your hands stop glowing red.");
  428.   }
  429.   if(QUERY_FLAG(tmp,FLAG_LIFESAVE)) {
  430.     if(flag>0) {
  431.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel very protected.");
  432.       SET_FLAG(op,FLAG_LIFESAVE);
  433.     } else {
  434.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You don't feel protected anymore.");
  435.       CLEAR_FLAG(op,FLAG_LIFESAVE);
  436.     }
  437.   }
  438.   if(QUERY_FLAG(tmp,FLAG_REFL_MISSILE)) {
  439.     if(flag>0) {
  440.       (*draw_info_func)(NDI_UNIQUE, 0, op,"A magic force shimmers around you.");
  441.       SET_FLAG(op,FLAG_REFL_MISSILE);
  442.     } else {
  443.       (*draw_info_func)(NDI_UNIQUE, 0, op,"The magic force fades away.");
  444.       CLEAR_FLAG(op,FLAG_REFL_MISSILE);
  445.     }
  446.   }
  447.   if(QUERY_FLAG(tmp,FLAG_REFL_SPELL)) {
  448.     if(flag>0) {
  449.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more safe now, somehow.");
  450.       SET_FLAG(op,FLAG_REFL_SPELL);
  451.     } else {
  452.       (*draw_info_func)(NDI_UNIQUE, 0, op,"Suddenly you feel less safe, somehow.");
  453.       CLEAR_FLAG(op,FLAG_REFL_SPELL);
  454.     }
  455.   }
  456.   if(QUERY_FLAG(tmp,FLAG_FLYING)) {
  457.     if(flag>0) {
  458.       if(QUERY_FLAG(op,FLAG_WIZ))
  459.         (*draw_info_func)(NDI_UNIQUE, 0, op,"You float a little higher in the air.");
  460.       else {
  461.         (*draw_info_func)(NDI_UNIQUE, 0, op,"You start to float in the air!.");
  462.         SET_FLAG(op,FLAG_FLYING);
  463.         if(op->speed>1)
  464.           op->speed=1;
  465.       }
  466.     } else {
  467.       if(QUERY_FLAG(op,FLAG_WIZ))
  468.         (*draw_info_func)(NDI_UNIQUE, 0, op,"You float a little lower in the air.");
  469.       else {
  470.         (*draw_info_func)(NDI_UNIQUE, 0, op,"You float down to the ground.");
  471.         CLEAR_FLAG(op,FLAG_FLYING);
  472.         if(op->speed<=1)
  473.           fix_player(op);
  474.       }
  475.     }
  476.   }
  477.   if(QUERY_FLAG(tmp,FLAG_STEALTH)) {
  478.     if(flag>0) {
  479.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You walk more quietly.");
  480.       SET_FLAG(op,FLAG_STEALTH);
  481.     } else {
  482.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You walk more noisily.");
  483.       CLEAR_FLAG(op,FLAG_STEALTH);
  484.     }
  485.   }
  486.   if(QUERY_FLAG(tmp,FLAG_MAKE_INVIS)) {
  487.     if(flag>0) {
  488.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You become transparent.");
  489.       SET_FLAG(op,FLAG_MAKE_INVIS);
  490.     op->invisible=1;
  491.     } else {
  492.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You can see yourself.");
  493.       CLEAR_FLAG(op,FLAG_MAKE_INVIS);
  494.     }
  495.   }
  496.   if(QUERY_FLAG(tmp,FLAG_BLIND)) {
  497.     if(flag>0) {
  498.       if(QUERY_FLAG(op,FLAG_WIZ))
  499.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Your mortal self is blinded.");
  500.       else { 
  501.         (*draw_info_func)(NDI_UNIQUE, 0, op,"You are blinded.");
  502.         SET_FLAG(op,FLAG_BLIND);
  503.         if(op->type==PLAYER)
  504.           op->contr->do_los=1;
  505.       }  
  506.     } else {
  507.       if(QUERY_FLAG(op,FLAG_WIZ))
  508.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Your mortal self can now see again.");
  509.       else {
  510.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Your vision returns.");
  511.         CLEAR_FLAG(op,FLAG_BLIND);
  512.         if(op->type==PLAYER)
  513.           op->contr->do_los=1;
  514.       }  
  515.     }  
  516.   }
  517.  
  518.   if(QUERY_FLAG(tmp,FLAG_SEE_IN_DARK)) {
  519.     if(flag>0) {
  520.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Your vision is better in the dark.");
  521.         SET_FLAG(op,FLAG_SEE_IN_DARK);
  522.         if(op->type==PLAYER)
  523.           op->contr->do_los=1;
  524.     } else {
  525.         (*draw_info_func)(NDI_UNIQUE, 0, op,"You see less well in the dark.");
  526.         CLEAR_FLAG(op,FLAG_SEE_IN_DARK);
  527.         if(op->type==PLAYER)
  528.           op->contr->do_los=1;
  529.     }  
  530.   }  
  531.  
  532.   if(QUERY_FLAG(tmp,FLAG_XRAYS)) {
  533.     if(flag>0) {
  534.       if(QUERY_FLAG(op,FLAG_WIZ))
  535.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Your vision becomes a little clearer.");
  536.       else {
  537.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Everything becomes transparent.");
  538.     SET_FLAG(op,FLAG_XRAYS);
  539.         if(op->type==PLAYER)
  540.           op->contr->do_los=1;
  541.       }
  542.     } else {
  543.       if(QUERY_FLAG(op,FLAG_WIZ))
  544.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Your vision becomes a bit out of focus.");
  545.       else {
  546.         (*draw_info_func)(NDI_UNIQUE, 0, op,"Everything suddenly looks very solid.");
  547.     CLEAR_FLAG(op,FLAG_XRAYS);
  548.         if(op->type==PLAYER)
  549.           op->contr->do_los=1;
  550.       }
  551.     }
  552.   }
  553.   if(tmp->stats.luck)
  554.     if(flag>0) {
  555.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more lucky.");
  556.       op->stats.luck+=tmp->stats.luck;
  557.     } else {
  558.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less lucky.");
  559.       op->stats.luck-=tmp->stats.luck;
  560.     }
  561.   if(tmp->stats.hp && op->type==PLAYER) {
  562.     op->contr->gen_hp+=tmp->stats.hp*flag;
  563.     if(flag*tmp->stats.hp>0)
  564.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel much more healthy!");
  565.     else
  566.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel much less healthy!");
  567.   }
  568.   if(tmp->stats.sp && op->type==PLAYER && tmp->type!=SKILL) {
  569.     op->contr->gen_sp+=tmp->stats.sp*flag;
  570.     if(flag*tmp->stats.sp>0)
  571.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel one with the powers of magic!");
  572.     else
  573.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You suddenly feel very mundane.");
  574.   }
  575.   /* for the future when artifacts set this -b.t. */
  576.   if(tmp->stats.grace && op->type==PLAYER) {
  577.     op->contr->gen_grace+=tmp->stats.grace*flag;
  578.      if(flag*tmp->stats.grace>0)
  579.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel closer to your god!");
  580.     else 
  581.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You suddenly feel less holy.");
  582.   } 
  583.   if(tmp->stats.food && op->type==PLAYER) {
  584.     op->contr->digestion+=tmp->stats.food*flag;
  585.     if(tmp->stats.food*flag>0)
  586.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel your digestion slowing down.");
  587.     else
  588.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel your digestion speeding up.");
  589.   }
  590.   if(tmp->immune&AT_PHYSICAL)
  591.     if(flag>0)
  592.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel much less solid.");
  593.     else
  594.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You suddenly feel very solid.");
  595.   else if(tmp->protected&AT_PHYSICAL)
  596.     if(flag>0)
  597.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less solid.");
  598.     else
  599.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more solid.");
  600.   if(tmp->immune&AT_MAGIC)
  601.     if(flag>0)
  602.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel immune to magic.");
  603.     else
  604.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less immune to magic.");
  605.   else if(tmp->protected&AT_MAGIC)
  606.     if(flag>0)
  607.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to magic.");
  608.     else
  609.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to magic.");
  610.   if(tmp->immune&AT_FIRE)
  611.     if(flag>0)
  612.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel immune to fire.");
  613.     else
  614.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less immune to fire.");
  615.   else if(tmp->protected&AT_FIRE)
  616.     if(flag>0)
  617.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to fire.");
  618.     else
  619.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to fire.");
  620.   if(tmp->vulnerable&AT_FIRE)
  621.     if(flag>0)
  622.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel exposed to fire.");
  623.     else
  624.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less exposed to fire.");
  625.   if(tmp->immune&AT_COLD)
  626.     if(flag>0)
  627.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel immune to cold.");
  628.     else
  629.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less immune to cold.");
  630.   else if(tmp->protected&AT_COLD)
  631.     if(flag>0)
  632.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to cold.");
  633.     else
  634.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to cold.");
  635.   if(tmp->vulnerable&AT_COLD)
  636.     if(flag>0)
  637.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel exposed to cold.");
  638.     else
  639.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less exposed to cold.");
  640.   if(tmp->immune&AT_ELECTRICITY)
  641.     if(flag>0)
  642.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel immune to electricity.");
  643.     else
  644.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less immune to electricity.");
  645.   else if(tmp->protected&AT_ELECTRICITY)
  646.     if(flag>0)
  647.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to electricity.");
  648.     else
  649.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to electricity.");
  650.   if(tmp->immune&AT_DRAIN)
  651.     if(flag>0)
  652.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel very full of life.");
  653.     else
  654.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You shiver, everything seems so bleak.");
  655.   else if(tmp->protected&AT_DRAIN)
  656.     if(flag>0)
  657.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to draining.");
  658.     else
  659.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to draining.");
  660.   if(tmp->immune&AT_POISON)
  661.     if(flag>0)
  662.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel extremely healthy.");
  663.     else
  664.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel extremely less healthy!");
  665.   else if(tmp->protected&AT_POISON)
  666.     if(flag>0)
  667.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to poison.");
  668.     else
  669.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to poison.");
  670.   if(tmp->immune&AT_SLOW)
  671.     if(flag>0)
  672.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel in sync with time.");
  673.     else
  674.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel out of sync with time.");
  675.   else if(tmp->protected&AT_SLOW)
  676.     if(flag>0)
  677.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more in sync with time.");
  678.     else
  679.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less in sync with time.");
  680.   if(tmp->immune&AT_PARALYZE)
  681.     if(flag>0)
  682.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel very unrestrained.");
  683.     else
  684.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more restrained.");
  685.   else if(tmp->protected&AT_PARALYZE)
  686.     if(flag>0)
  687.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel more resistant to paralyzation.");
  688.     else
  689.       (*draw_info_func)(NDI_UNIQUE, 0, op,"You feel less resistant to paralyzation.");
  690.  
  691.   if(tmp->type!=EXPERIENCE)
  692.     for (j=0; j<7; j++) {
  693.       if ((i=get_attr_value(&(tmp->stats),j))!=0) {
  694.     if (i * flag > 0)
  695.         (*draw_info_func)(NDI_UNIQUE, 0, op, gain_msg[j]);
  696.     else
  697.         (*draw_info_func)(NDI_UNIQUE, 0, op, lose_msg[j]);
  698.       }
  699.     }
  700.   return 1;
  701. }
  702.  
  703. /*
  704.  * Stat draining by Vick 930307
  705.  * (Feeling evil, I made it work as well now.  -Frank 8)
  706.  */
  707.  
  708. void drain_stat(object *op) {
  709.   drain_specific_stat(op, RANDOM()%6);
  710. }
  711.  
  712. void drain_specific_stat(object *op, int deplete_stats) {
  713.   object *tmp;
  714.   archetype *at;
  715.  
  716.   at = find_archetype("depletion");
  717.   if (!at) {
  718.     LOG(llevError, "Couldn't find archetype depletion.\n");
  719.     return;
  720.   } else {
  721.     tmp = present_arch_in_ob(at, op);
  722.     if (!tmp) {
  723.       tmp = arch_to_object(at);
  724.       tmp = insert_ob_in_ob(tmp, op);
  725.       SET_FLAG(tmp,FLAG_APPLIED);
  726.     }
  727.   }
  728.  
  729.   (*draw_info_func)(NDI_UNIQUE, 0, op, drain_msg[deplete_stats]);
  730.   change_attr_value(&tmp->stats, deplete_stats, -1);
  731.   fix_player(op);
  732.   if (op->type==PLAYER) (void)(*draw_stats_func)(op);
  733. }
  734.  
  735. /*
  736.  * A value of 0 indicates timeout, otherwise change the luck of the object.
  737.  * via an applied bad_luck object.
  738.  */
  739.  
  740. void change_luck(object *op, int value) {
  741.   object *tmp;
  742.   archetype *at;
  743.   at = find_archetype("luck");
  744.   if (!at)
  745.     LOG(llevError, "Couldn't find archetype luck.\n");
  746.   else {
  747.     tmp = present_arch_in_ob(at, op);
  748.     if (!tmp) {
  749.       if (!value)
  750.         return;
  751.       tmp = arch_to_object(at);
  752.       tmp = insert_ob_in_ob(tmp, op);
  753.       SET_FLAG(tmp,FLAG_APPLIED);
  754.     }
  755.     if (value) {
  756.       op->stats.luck+=value;
  757.       tmp->stats.luck+=value;
  758.     } else {
  759.       if (!tmp->stats.luck) {
  760.         LOG(llevDebug, "Internal error in change_luck().\n");
  761.         return;
  762.       }
  763.       if (RANDOM()%(FABS(tmp->stats.luck)) > RANDOM()%30)
  764.         tmp->stats.luck += tmp->stats.luck>0?-1:1;
  765.     }
  766.   }
  767. }
  768.  
  769. /*
  770.  * Subtracts stat-bonuses given by the class which the player has chosen.
  771.  */
  772.  
  773. void remove_statbonus(object *op) {
  774.   op->stats.Str -= op->arch->clone.stats.Str;
  775.   op->stats.Dex -= op->arch->clone.stats.Dex;
  776.   op->stats.Con -= op->arch->clone.stats.Con;
  777.   op->stats.Wis -= op->arch->clone.stats.Wis;
  778.   op->stats.Pow -= op->arch->clone.stats.Pow;
  779.   op->stats.Cha -= op->arch->clone.stats.Cha;
  780.   op->stats.Int -= op->arch->clone.stats.Int;
  781.   op->contr->orig_stats.Str -= op->arch->clone.stats.Str;
  782.   op->contr->orig_stats.Dex -= op->arch->clone.stats.Dex;
  783.   op->contr->orig_stats.Con -= op->arch->clone.stats.Con;
  784.   op->contr->orig_stats.Wis -= op->arch->clone.stats.Wis;
  785.   op->contr->orig_stats.Pow -= op->arch->clone.stats.Pow;
  786.   op->contr->orig_stats.Cha -= op->arch->clone.stats.Cha;
  787.   op->contr->orig_stats.Int -= op->arch->clone.stats.Int;
  788. }
  789.  
  790. /*
  791.  * Adds stat-bonuses given by the class which the player has chosen.
  792.  */
  793.  
  794. void add_statbonus(object *op) {
  795.   op->stats.Str += op->arch->clone.stats.Str;
  796.   op->stats.Dex += op->arch->clone.stats.Dex;
  797.   op->stats.Con += op->arch->clone.stats.Con;
  798.   op->stats.Wis += op->arch->clone.stats.Wis;
  799.   op->stats.Pow += op->arch->clone.stats.Pow;
  800.   op->stats.Cha += op->arch->clone.stats.Cha;
  801.   op->stats.Int += op->arch->clone.stats.Int;
  802.   op->contr->orig_stats.Str += op->arch->clone.stats.Str;
  803.   op->contr->orig_stats.Dex += op->arch->clone.stats.Dex;
  804.   op->contr->orig_stats.Con += op->arch->clone.stats.Con;
  805.   op->contr->orig_stats.Wis += op->arch->clone.stats.Wis;
  806.   op->contr->orig_stats.Pow += op->arch->clone.stats.Pow;
  807.   op->contr->orig_stats.Cha += op->arch->clone.stats.Cha;
  808.   op->contr->orig_stats.Int += op->arch->clone.stats.Int;
  809. }
  810.  
  811. /*
  812.  * Updates all abilities given by applied objects in the inventory
  813.  * of the given object.  Note: This function works for both monsters
  814.  * and players; the "player" in the name is purely an archaic inheritance.
  815.  */
  816. /* July 95 - inserted stuff to handle new skills/exp system - b.t.
  817.    spell system split, grace points now added to system  --peterm
  818.  */
  819.  
  820. void fix_player(object *op) {
  821.   int i,j;
  822.   float f,max=9,added_speed=0,bonus_speed=0;
  823.   float M,W,s,D,K,S,M2;
  824.   int weapon_weight=0,weapon_speed=0;
  825.   int best_wc=0, best_ac=0;
  826.   object *grace_obj=NULL,*mana_obj=NULL,*hp_obj=NULL,*wc_obj=NULL,*tmp;
  827.   if(op->type==PLAYER) {
  828.     for(i=0;i<7;i++) {
  829.       set_attr_value(&(op->stats),i,get_attr_value(&(op->contr->orig_stats),i));
  830.       }
  831. #ifdef SPELL_ENCUMBRANCE
  832.     op->contr->encumbrance=0;
  833. #endif
  834. #ifdef ALLOW_SKILLS
  835.     if(op->chosen_skill&&op->chosen_skill->exp_obj)
  836.     op->chosen_skill->level=op->chosen_skill->exp_obj->level;
  837. #endif
  838.     op->attacktype=0;    
  839.   }
  840.   if(op->slaying!=NULL) {
  841.     free_string(op->slaying);
  842.     op->slaying=NULL;
  843.   }
  844.   if(!QUERY_FLAG(op,FLAG_WIZ)) {
  845.     CLEAR_FLAG(op, FLAG_FLYING);
  846.     CLEAR_FLAG(op, FLAG_XRAYS);
  847.     CLEAR_FLAG(op, FLAG_MAKE_INVIS);
  848.   }
  849.  
  850.   op->protected=op->arch->clone.protected;
  851.   op->vulnerable=op->arch->clone.vulnerable;
  852.   op->immune=op->arch->clone.immune;
  853.   op->armour=op->arch->clone.armour;
  854.   op->stats.wc=op->arch->clone.stats.wc;
  855.   op->stats.dam=op->arch->clone.stats.dam;
  856.  
  857.  
  858.   if(!QUERY_FLAG(op,FLAG_USE_ARMOUR) && op->type==PLAYER) 
  859.       op->stats.ac=MAX(-10,op->arch->clone.stats.ac - op->level/3);
  860.   else
  861.       op->stats.ac=op->arch->clone.stats.ac;
  862.  
  863.  
  864.   op->stats.luck=op->arch->clone.stats.luck;
  865.   op->speed = op->arch->clone.speed;
  866.  
  867.   for(tmp=op->inv;tmp!=NULL;tmp=tmp->below)
  868.     if(QUERY_FLAG(tmp,FLAG_APPLIED) && tmp->type!=CONTAINER && tmp->type!=CLOSE_CON) {
  869.       if(op->type==PLAYER
  870. #ifdef ALLOW_SKILLS /* The meaning of stats in skill or experience objects is different -
  871.              * we use them solely to link skills to experience, thus it is 
  872.              * inappropriate to allow these applied objects to change stats */ 
  873.            && tmp->type!=EXPERIENCE 
  874. /*
  875. && tmp->type!=SKILL
  876.  */
  877. #endif
  878.       )
  879.         for(i=0;i<7;i++)
  880.           change_attr_value(&(op->stats),i,get_attr_value(&(tmp->stats),i));
  881.       op->protected|=tmp->protected;
  882.       op->vulnerable|=tmp->vulnerable;
  883.       op->attacktype|=tmp->attacktype;
  884.       op->immune|=tmp->immune;
  885.       op->path_attuned|=tmp->path_attuned;
  886.       op->path_repelled|=tmp->path_repelled;
  887.       op->path_denied|=tmp->path_denied;
  888.       op->stats.luck+=tmp->stats.luck;
  889.       if(QUERY_FLAG(tmp,FLAG_LIFESAVE))
  890.         SET_FLAG(op,FLAG_LIFESAVE);
  891.       if(QUERY_FLAG(tmp,FLAG_REFL_SPELL))
  892.         SET_FLAG(op,FLAG_REFL_SPELL);
  893.       if(QUERY_FLAG(tmp,FLAG_REFL_MISSILE))
  894.         SET_FLAG(op,FLAG_REFL_MISSILE);
  895.       if(QUERY_FLAG(tmp,FLAG_STEALTH))
  896.         SET_FLAG(op,FLAG_STEALTH);
  897.       if(QUERY_FLAG(tmp,FLAG_MAKE_INVIS)) {
  898.         SET_FLAG(op,FLAG_MAKE_INVIS); op->invisible=1; }
  899.  
  900.       if(QUERY_FLAG(tmp,FLAG_FLYING)) {
  901.         SET_FLAG(op,FLAG_FLYING);
  902.         if(!QUERY_FLAG(op,FLAG_WIZ))
  903.           max=1;
  904.       }
  905.       if(QUERY_FLAG(tmp,FLAG_XRAYS))
  906.         SET_FLAG(op,FLAG_XRAYS);
  907.     
  908.       if(QUERY_FLAG(tmp,FLAG_BLIND)) 
  909.     SET_FLAG(op,FLAG_BLIND);
  910.  
  911.       if(QUERY_FLAG(tmp,FLAG_SEE_IN_DARK)) 
  912.     SET_FLAG(op,FLAG_SEE_IN_DARK);
  913.  
  914.       if(tmp->stats.exp 
  915. #ifdef ALLOW_SKILLS /* we get BIG problems w/o this line! */
  916.        && tmp->type!=EXPERIENCE
  917. #endif
  918.       ) {
  919.         if(tmp->stats.exp > 0) {
  920.           added_speed+=(float)tmp->stats.exp/3.0;
  921.           bonus_speed+=1.0+(float)tmp->stats.exp/3.0;
  922.         } else
  923.           added_speed+=(float)tmp->stats.exp;
  924.       }
  925.       switch(tmp->type) {
  926.  
  927.      /* EXPERIENCE objects. What we are doing here is looking for "relevant" 
  928.       * experience objects. Some of these will be used to calculate 
  929.       * level-based changes in player status. For expample, the 
  930.       * experience object which has exp_obj->stats.Str set controls the 
  931.       * wc bonus of the player. -b.t.
  932.       */
  933. #ifdef ALLOW_SKILLS
  934.       case EXPERIENCE: 
  935.     if(op->type!=PLAYER)    /* Only players should have these. */ 
  936.       LOG(llevError,"Error: %s has exp_obj in invenory\n",op->name); 
  937.     else {
  938.        if (tmp->stats.Str && !wc_obj) 
  939.         wc_obj = tmp;
  940.        if (tmp->stats.Con && !hp_obj) 
  941.         hp_obj = tmp;
  942.        if (tmp->stats.Pow && !mana_obj)  /* for spellpoint determ */ 
  943.         mana_obj = tmp;
  944.        if (tmp->stats.Wis && !grace_obj)
  945.         grace_obj = tmp; 
  946.     }
  947.         break;
  948.             
  949.       case SKILL:         /* skills modifying the character -b.t. */ 
  950.                 /* for all skills and skill granting objects */ 
  951.  
  952.     if(tmp==op->chosen_skill) { 
  953.  
  954.       op->stats.wc-=tmp->stats.wc; 
  955.  
  956.       if(tmp->stats.dam>0) {     /* skill is a 'weapon' */ 
  957.         if(!QUERY_FLAG(op,FLAG_READY_WEAPON)) 
  958.                 weapon_speed = (int) WEAPON_SPEED(tmp);
  959.         if(weapon_speed<0) weapon_speed = 0;
  960.             weapon_weight=tmp->weight;
  961.             op->stats.dam+=tmp->stats.dam*(1 + (op->chosen_skill->level/9));
  962.         if(tmp->magic) op->stats.dam += tmp->magic;
  963.       }
  964.  
  965.           if(tmp->stats.wc)
  966.             op->stats.wc-=(tmp->stats.wc+tmp->magic);
  967.  
  968.           if(tmp->armour)
  969.             op->armour+=((100-op->armour)*tmp->armour)/100;
  970.  
  971.           if(tmp->slaying!=NULL)
  972.             add_refcount(op->slaying = tmp->slaying);
  973.  
  974.       if(tmp->stats.ac)
  975.             op->stats.ac-=(tmp->stats.ac+tmp->magic);
  976.  
  977. #ifdef SPELL_ENCUMBRANCE
  978.         if(op->type==PLAYER) op->contr->encumbrance+=(int)3*tmp->weight/1000;
  979. #endif
  980.     }
  981.     break;
  982. #endif /* ALLOW_SKILLS */
  983.       case SHIELD:
  984. #ifdef SPELL_ENCUMBRANCE
  985.     if(op->type==PLAYER) op->contr->encumbrance+=(int)tmp->weight/2000;
  986. #endif
  987.       case RING:
  988.       case AMULET:
  989.       case GIRDLE:
  990.       case HELMET:
  991.       case BOOTS:
  992.       case GLOVES:
  993.       case CLOAK:
  994.         if(tmp->armour)
  995.           op->armour+=((100-op->armour)*tmp->armour)/100;
  996.         if(tmp->stats.wc)
  997.           op->stats.wc-=(tmp->stats.wc+tmp->magic);
  998.         if(tmp->stats.dam)
  999.           op->stats.dam+=(tmp->stats.dam+tmp->magic);
  1000.         if(tmp->stats.ac)
  1001.           op->stats.ac-=(tmp->stats.ac+tmp->magic);
  1002.         break;
  1003.       case WEAPON:
  1004.         op->stats.wc-=(tmp->stats.wc+tmp->magic);
  1005.         if(tmp->stats.ac&&tmp->stats.ac+tmp->magic>0)
  1006.           op->stats.ac-=tmp->stats.ac+tmp->magic;
  1007.         if(tmp->armour)
  1008.           op->armour+=((100-op->armour)*tmp->armour)/100;
  1009.         op->stats.dam+=(tmp->stats.dam+tmp->magic);
  1010.         weapon_weight=tmp->weight;
  1011.         weapon_speed=((int)WEAPON_SPEED(tmp)*2-tmp->magic)/2;
  1012.         if(weapon_speed<0) weapon_speed=0;
  1013.         if(tmp->slaying!=NULL)
  1014.           add_refcount(op->slaying = tmp->slaying);
  1015. #ifdef SPELL_ENCUMBRANCE
  1016.     if(op->type==PLAYER) op->contr->encumbrance+=(int)3*tmp->weight/1000;
  1017. #endif
  1018.         break;
  1019.       case ARMOUR: /* Only the best of these three are used: */
  1020. #ifdef SPELL_ENCUMBRANCE
  1021.     if(op->type==PLAYER) op->contr->encumbrance+=(int)tmp->weight/1000;
  1022. #endif
  1023.       case BRACERS:
  1024.       case FORCE:
  1025.         if(tmp->armour)
  1026.           op->armour+=((100-op->armour)*tmp->armour)/100;
  1027.         if(tmp->stats.wc) { 
  1028.           if(best_wc<tmp->stats.wc+tmp->magic) {
  1029.              op->stats.wc+=best_wc;
  1030.             best_wc=tmp->stats.wc+tmp->magic;
  1031.       } else
  1032.             op->stats.wc+=tmp->stats.wc+tmp->magic;
  1033.     }
  1034.         if(tmp->stats.ac) {
  1035.           if(best_ac<tmp->stats.ac+tmp->magic) {
  1036.             op->stats.ac+=best_ac; /* Remove last bonus */
  1037.             best_ac=tmp->stats.ac+tmp->magic;
  1038.           }
  1039.           else /* To nullify the below effect */
  1040.             op->stats.ac+=tmp->stats.ac+tmp->magic;
  1041.         }
  1042.         if(tmp->stats.wc) op->stats.wc-=(tmp->stats.wc+tmp->magic);
  1043.         if(tmp->stats.ac) op->stats.ac-=(tmp->stats.ac+tmp->magic);
  1044.         if(ARMOUR_SPEED(tmp)&&ARMOUR_SPEED(tmp)/10.0<max)
  1045.           max=ARMOUR_SPEED(tmp)/10.0;
  1046.         break;
  1047.       }
  1048.     }
  1049.   /* awarding hp -- I changed this so that the mean between the 'fighter'
  1050.    * level (hp_obj->level) and overall scores are used. The system of hp
  1051.    * progression remains unchanged for no skills. b.t.
  1052.    */
  1053.   if(op->type==PLAYER) {
  1054.     int pl_level;
  1055.     check_stat_bounds(&(op->stats));
  1056.     if(!hp_obj) hp_obj = op; /* happens when skills are not used */ 
  1057. #if 0
  1058.     pl_level = (op->level + hp_obj->level)/2;
  1059. #else
  1060.     pl_level=op->level;
  1061. #endif
  1062.     if(pl_level<1) pl_level=1; /* safety, we should always get 1 levels worth of hp! */ 
  1063.     for(i=1,op->stats.maxhp=0;i<=pl_level&&i<=10;i++) {
  1064.       j=op->contr->levhp[i]+con_bonus[op->stats.Con]/2;
  1065.       if(i%2&&con_bonus[op->stats.Con]%2)
  1066.         j++;
  1067.       op->stats.maxhp+=j>1?j:1;
  1068.     }
  1069.     for(i=11;i<=op->level;i++)
  1070.       op->stats.maxhp+=2;
  1071.     if(op->stats.hp>op->stats.maxhp)
  1072.       op->stats.hp=op->stats.maxhp;
  1073.  
  1074.     /* Sp gain is controlled by the level of the player's 
  1075.      * relevant experience object (mana_obj, see above) 
  1076.      */ 
  1077.     /* following happen when skills system is not used */
  1078.     if(!mana_obj) mana_obj = op;
  1079.     if(!grace_obj) grace_obj = op;
  1080.  
  1081.      /* set maxsp */
  1082.     if(!mana_obj || !mana_obj->level || op->type!=PLAYER) mana_obj = op;
  1083.     for(i=1,op->stats.maxsp=0;i<=mana_obj->level&&i<=10;i++) {
  1084.       j=op->contr->levsp[i]+sp_bonus[op->stats.Pow]/2;
  1085.       if((i%2) && (sp_bonus[op->stats.Pow]%2))
  1086.       if (sp_bonus[op->stats.Pow]>0)
  1087.             j++;
  1088.       else
  1089.           j--;
  1090.       op->stats.maxsp+=j>1?j:1;
  1091.     }
  1092.     for(i=11;i<=mana_obj->level;i++)
  1093.       op->stats.maxsp+=2;
  1094.     /* Characters can get their sp supercharged via rune of transferrance */
  1095.     if(op->stats.sp>op->stats.maxsp*2)
  1096.       op->stats.sp=op->stats.maxsp*2;
  1097.  
  1098.      /* set maxgrace, notice 3-4 lines below it depends on both Wis and Pow */
  1099.      if(!grace_obj || !grace_obj->level || op->type!=PLAYER) grace_obj = op;
  1100.      for(i=1,op->stats.maxgrace=0;i<=grace_obj->level&&i<=10;i++) {
  1101.          j=op->contr->levgrace[i]
  1102.              +(grace_bonus[op->stats.Pow] + grace_bonus[op->stats.Wis])/8;
  1103.         /* changed the starting grace for playability -b.t. */ 
  1104.          if(i<2) j += 1+((grace_bonus[op->stats.Pow] + grace_bonus[op->stats.Wis])/4); 
  1105.          /*  I'll omit the odd even stuff from above for now  --PeterM */
  1106.          op->stats.maxgrace+=j>1?j:1;
  1107.      }
  1108.      /* one grace point per level after 11 */
  1109.      for(i=11;i<=grace_obj->level;i++)
  1110.          op->stats.maxgrace+=2;
  1111.  
  1112.      /* I'll also allow grace to be larger than the maximum, for who am I
  1113.          to put limits on the whims of the gods?  I omit any fix for overlarge
  1114.          grace--PeterM */
  1115.  
  1116.     if(op->contr->braced)
  1117.       op->stats.ac+=2;
  1118.     else
  1119.       op->stats.ac-=dex_bonus[op->stats.Dex];
  1120.  
  1121.    /* In new exp/skills system, wc bonuses are related to 
  1122.     * the players level in a relevant exp object (wc_obj)
  1123.     * not the general player level -b.t.  */
  1124.    /* I changed this slightly so that wc bonuses are better
  1125.     * than before. This is to balance out the fact that 
  1126.     * the player no longer gets a personal weapon w/ 1
  1127.     * improvementevery level, now its fighterlevel/5. So
  1128.     * we give the player a bonus here in wc and dam
  1129.     * to make up for the change. Note that I left the 
  1130.     * monster bonus the same as before. -b.t.
  1131.     */
  1132.  
  1133. #ifdef ALLOW_SKILLS
  1134.     if(op->type==PLAYER && wc_obj && wc_obj->level>1) { 
  1135.       int i;
  1136.       op->stats.wc-=(wc_obj->level+thaco_bonus[op->stats.Str]);
  1137.       for(i=1;i<wc_obj->level;i++) { 
  1138.     /* addtional wc every 6 levels */ 
  1139.     if(!(i%6)) op->stats.wc--; 
  1140.     /* addtional dam every 4 levels. */ 
  1141.     if(!(i%4)&&!(dam_bonus[op->stats.Str]<0)) 
  1142.         op->stats.dam+=(1+(dam_bonus[op->stats.Str]/5));
  1143.       }
  1144.     } else 
  1145. #endif /* ALLOW_SKILLS */ 
  1146.     op->stats.wc-=(op->level+thaco_bonus[op->stats.Str]);
  1147.  
  1148.     op->stats.dam+=dam_bonus[op->stats.Str];
  1149.     if(op->contr->braced)
  1150.       op->stats.wc+=4;
  1151.     if(op->stats.dam<1)
  1152.       op->stats.dam=1;
  1153.     op->speed=1.0+speed_bonus[op->stats.Dex];
  1154. #ifdef SEARCH_ITEMS
  1155.     if (op->contr->search_str[0])
  1156.       op->speed -= 1;
  1157. #endif
  1158.     if (op->attacktype==0)
  1159.     op->attacktype=op->arch->clone.attacktype;
  1160.   }
  1161.   if(added_speed>=0)
  1162.     op->speed+=added_speed/10.0;
  1163.   else /* Something wrong here...: */
  1164.     op->speed /= (float)(1.0-added_speed);
  1165.   if(op->speed>max)
  1166.     op->speed=max;
  1167.  
  1168.   if(op->type == PLAYER) {
  1169.     f=(op->carrying/1000)-max_carry[op->stats.Str];
  1170.     if(f>0) op->speed=op->speed/(1.0+f/max_carry[op->stats.Str]);
  1171.   }
  1172.  
  1173.   op->speed+=bonus_speed/10.0; /* Not affected by limits */
  1174.  
  1175.   if(op->type == PLAYER) {
  1176. /* (This formula was made by vidarl@ifi.uio.no) */
  1177.     M=(max_carry[op->stats.Str]-121)/121.0;
  1178.     M2=max_carry[op->stats.Str]/100.0;
  1179.     W=weapon_weight/20000.0;
  1180.     s=2-weapon_speed/10.0;
  1181.     D=(op->stats.Dex-14)/14.0;
  1182.     K=1 + M/3.0 - W/(3*M2) + op->speed/5.0 + D/2.0;
  1183.     K*=(4+op->level)/(float)(6+op->level)*1.2;
  1184.     if(K<=0) K=0.01;
  1185.       S=op->speed/(K*s);
  1186.     op->contr->weapon_sp=S;
  1187.     if(op->stats.hp!=-10000 && op->type==PLAYER)
  1188.       (*draw_stats_func)(op);
  1189.   }
  1190.   /* I want to limit the power of small monsters with big weapons: */
  1191.   if(op->type!=PLAYER&&op->arch!=NULL&&
  1192.      op->stats.dam>op->arch->clone.stats.dam*3)
  1193.       op->stats.dam=op->arch->clone.stats.dam*3;
  1194.  
  1195.   update_ob_speed(op);
  1196.  
  1197. }
  1198.  
  1199. /*
  1200.  * Returns true if the given player is a legal class.
  1201.  * The function to add and remove class-bonuses to the stats doesn't
  1202.  * check if the stat becomes negative, thus this function
  1203.  * merely checks that all stats are 1 or more, and returns
  1204.  * false otherwise.
  1205.  */
  1206.  
  1207. int allowed_class(object *op) {
  1208.   return op->stats.Dex>0&&op->stats.Str>0&&op->stats.Con>0&&
  1209.          op->stats.Int>0&&op->stats.Wis>0&&op->stats.Pow>0&&
  1210.      op->stats.Cha>0;
  1211. }
  1212.  
  1213. /*
  1214.  * Returns how much experience is needed for a player to become
  1215.  * the given level.
  1216.  */
  1217.  
  1218. long level_exp(int level,double expmul) {
  1219. /*  int   count,required_exp;*/
  1220.  
  1221.   static long int bleep=1650000; 
  1222. /* Eneq(@csd.uu.se):  New level-algorithm; level 2 at 1000 then  
  1223.    times 2 for all following. */
  1224.  
  1225.   if(level<=100) return expmul * levels[level];
  1226.  
  1227. /*  for (count=10, required_exp=levels[count];count<level;count++)
  1228.     required_exp*=1.5; */
  1229. /*  return required_exp; */
  1230.     return expmul*(levels[100]+bleep*(level-100));
  1231. }
  1232.  
  1233. #ifdef ALLOW_SKILLS /* new experience system */ 
  1234.  
  1235. /* add_exp() - new algorithm. Revamped experience gain/loss routine. 
  1236.  * Based on the old add_exp() function - but tailored to add experience 
  1237.  * to experience objects. The way this works-- the code checks the 
  1238.  * current skill readied by the player (chosen_skill) and uses that to
  1239.  * identify the appropriate experience object. Then the experience in
  1240.  * the object, and the player's overall score are updated. In the case
  1241.  * of exp loss, all exp categories which have experience are equally
  1242.  * reduced. The total experience score of the player == sum of all 
  1243.  * exp object experience.  - b.t. thomas@astro.psu.edu 
  1244.  */
  1245.  
  1246. void add_exp(object *op, int exp) {
  1247.   object *exp_ob=NULL; /* the object into which experience will go */ 
  1248.   object *tmp,*pl_exp[MAX_EXP_CAT];
  1249.   int old_exp,del_exp=0,nrofexp=0,i;
  1250.  
  1251.   /* first, some general stuff */
  1252.   if (exp > (op->stats.exp / 2))
  1253.     if (op->stats.exp < 50)
  1254.       exp = 50;  
  1255.     else
  1256.       exp = op->stats.exp / 2;
  1257.   if(op->type==PLAYER && op->contr->braced) exp=exp/5; 
  1258.  
  1259. #ifdef EXP_DEBUG
  1260.   LOG(llevDebug,"add_exp() called for %s, exp = %d\n",query_name(op),exp); 
  1261. #endif
  1262.  
  1263.   if(op->type != PLAYER)         /* for Monsters only */
  1264.      exp =  adjust_exp(op,exp);
  1265.   else {                /* Players only */ 
  1266.      if(exp>0) { /* ADDING exp (to one object) */ 
  1267.  
  1268.     if(!op->chosen_skill) { 
  1269.        LOG(llevError,"add_exp() called w/ no ready skill.\n");
  1270.        return;
  1271.     } else if(!op->exp_obj && !op->chosen_skill->exp_obj) { 
  1272.        LOG(llevError,"add_exp() called for skill w/o exp obj.\n");
  1273.        return;
  1274.     }
  1275.  
  1276.     /* if op->exp_obj is set, then the player has killed with an 
  1277.      * animated object cf. fireball */
  1278.     if(op->exp_obj)  
  1279.        exp_ob = op->exp_obj;
  1280.     else
  1281.        exp_ob = op->chosen_skill->exp_obj; 
  1282.  
  1283.     /* Adding exp properly - we have to make sure that:
  1284.          *    1) op->stats.exp<MAX_EXPERIENCE 
  1285.         *    2) exp_ob->stats.exp<MAX_EXP_IN_OBJ
  1286.      *     3) sum of exp obj experience = op->stats.exp
  1287.      */
  1288.  
  1289.         exp = adjust_exp(op,exp);    /* op->stats.exp < MAX_EXPERIENCE */ 
  1290.     old_exp = exp;    
  1291.         exp = adjust_exp(exp_ob,exp);   /* exp_ob->stats.exp < MAX_EXP_IN_OBJ */ 
  1292.                     /* check and  adjustment */ 
  1293.     if(old_exp>exp) op->stats.exp+=(exp-old_exp); 
  1294.     player_lvl_adj(op,NULL);   
  1295.     player_lvl_adj(op,exp_ob);   
  1296.   
  1297.      } else if (op->type ==PLAYER && exp < 0) { /* SUBTRACT exp (from all exp obj) */ 
  1298.       float fraction = (float) exp/(float) op->stats.exp;
  1299.  
  1300.     /* Sub exper - we will remove the same fraction of experience
  1301.      * from all experience objects. 
  1302.       */
  1303.  
  1304.     for(tmp=op->inv;tmp;tmp=tmp->below)
  1305.       if(tmp->type==EXPERIENCE && tmp->stats.exp) { 
  1306.         pl_exp[nrofexp] = tmp;
  1307.         nrofexp++; 
  1308.       } 
  1309.     /* we do experience objects first here */
  1310.     for(i=0;i<nrofexp;i++) { 
  1311.        del_exp += adjust_exp(pl_exp[i],(pl_exp[i]->stats.exp*fraction)); 
  1312.          player_lvl_adj(op,pl_exp[i]); /* adj exp object */ 
  1313.     }
  1314.  
  1315.     (void) adjust_exp(op, del_exp);
  1316.     player_lvl_adj(op,NULL); 
  1317.  
  1318.      } else if (op->type !=PLAYER && exp < 0) { /* SUBTRACT monster exp */ 
  1319.  
  1320.         (void) adjust_exp(op, exp);
  1321.         player_lvl_adj(op,NULL);
  1322.  
  1323.      } else { /* No exp gain, but check lvl adj */ 
  1324.  
  1325.     if(op->chosen_skill && op->chosen_skill->exp_obj)
  1326.           player_lvl_adj(op, op->chosen_skill->exp_obj);
  1327.       player_lvl_adj(op,NULL); 
  1328.      }
  1329.  
  1330.      /* reset the player exp_obj to NULL */
  1331.      if(op->exp_obj) op->exp_obj = NULL;
  1332.   }
  1333.  
  1334. }
  1335.  
  1336. #else /*ALLOW_SKILLS */ /* add_exp() - the old exp system */
  1337.  
  1338. /*
  1339.  * Adds (or subtracts) experience to a living object.  If it is a player,
  1340.  * checks for level-gain/loss is done.
  1341.  * The routines for gaining/losing levels is also within this function.
  1342.  */
  1343.  
  1344. void add_exp(object *op,int exp) {
  1345.   char buf[MAX_BUF];
  1346.  
  1347.   if (exp > op->stats.exp / 2)
  1348.     if (op->stats.exp < 100)
  1349.       exp = 50;
  1350.     else
  1351.       exp = op->stats.exp / 2;
  1352.   if(op->type==PLAYER && op->contr->braced) exp=exp/5; 
  1353.   /* shuffled some stuff into here  -b.t. */
  1354.   exp = adjust_exp(op,exp);
  1355.  
  1356.   if(op->type==PLAYER) {
  1357.     if(op->level < MAXLEVEL && op->stats.exp >= level_exp(op->level+1,op->expmul)) {
  1358.       op->level++;
  1359.       if(op->level < 11)
  1360.       {  
  1361.         op->contr->levhp[op->level] = (int) RANDOM()%4 + (int) RANDOM()%4 + 3;
  1362.         op->contr->levsp[op->level] = (int) RANDOM()%3 + (int) RANDOM()%3 + 2;
  1363.           op->contr->levgrace[op->level]=(int)RANDOM()%2 + (int) RANDOM()%2 + 1;
  1364.       }  
  1365.       fix_player(op);
  1366.       if(op->level>1) {
  1367.         sprintf(buf,"You are now level %d.",op->level);
  1368.         (*draw_info_func)(NDI_UNIQUE, 0, op,buf);
  1369.       }
  1370.       add_exp(op,0); /* To increase more levels */
  1371.     } else if(op->level>1&&op->stats.exp<level_exp(op->level,op->expmul)) {
  1372.       op->level--;
  1373.       fix_player(op);
  1374.       sprintf(buf,"You are now level %d.",op->level);
  1375.       (*draw_info_func)(NDI_UNIQUE, 0, op,buf);
  1376.       add_exp(op,0); /* To decrease more levels */
  1377.     } 
  1378.   } 
  1379. }    
  1380.  
  1381. #endif /* ALLOW_SKILLS */ 
  1382.  
  1383. /* player_lvl_adj() - for the new exp system. we are concerned with
  1384.  * whether the player gets more hp, sp and new levels.
  1385.  * -b.t.
  1386.  */
  1387.  
  1388. void player_lvl_adj(object *who, object *op) {
  1389.   char buf[MAX_BUF];
  1390.  
  1391.     if(!op)        /* when rolling stats */ 
  1392.       op = who;    
  1393.  
  1394.     if(op->level < MAXLEVEL && op->stats.exp >= level_exp(op->level+1,op->expmul)) {
  1395.     op->level++;
  1396.  
  1397.       if(who && (who->level < 11) && op->type!=EXPERIENCE) { 
  1398.           who->contr->levhp[who->level] = (int) RANDOM()%4 + (int) RANDOM()%4 + 3;
  1399.           who->contr->levsp[who->level] = (int) RANDOM()%3 + (int) RANDOM()%3 + 2;
  1400.              who->contr->levgrace[who->level]=(int)RANDOM()%2 + (int) RANDOM()%2 + 1;
  1401.       }
  1402.  
  1403.       if(who) fix_player(who);
  1404.       if(op->level>1 && op->type==EXPERIENCE) {
  1405.         sprintf(buf,"You are now level %d in %s based skills.",op->level,op->name);
  1406.         if(who) (*draw_info_func)(NDI_UNIQUE, 0, who,buf);
  1407.       }  
  1408.       player_lvl_adj(who,op); /* To increase more levels */
  1409.     } else if(op->level>1&&op->stats.exp<level_exp(op->level,op->expmul)) {
  1410.       op->level--;
  1411.       if(who) fix_player(who);
  1412.       if(op->type==EXPERIENCE) {
  1413.         sprintf(buf,"You are now level %d in %s based skills.",op->level,op->name);
  1414.         if(who) (*draw_info_func)(NDI_UNIQUE, 0, who,buf);
  1415.       }
  1416.       player_lvl_adj(who,op); /* To decrease more levels */
  1417.     }
  1418. }
  1419.  
  1420. /* adjust_exp() - make sure that we don't exceed max or min set on
  1421.  * experience
  1422.  */
  1423.  
  1424. int adjust_exp(object *op, int exp) {
  1425.   int max_exp = MAX_EXPERIENCE;
  1426.  
  1427.   op->stats.exp += exp;
  1428.   if(op->stats.exp < 0) {
  1429.     exp -= op->stats.exp;
  1430.     op->stats.exp = 0;
  1431.   } 
  1432.   /* reset max_exp value if we have experience obj */
  1433.   if(op->type==EXPERIENCE) 
  1434.       max_exp = MAX_EXP_IN_OBJ;
  1435.  
  1436.   if(op->stats.exp>max_exp) {
  1437.     exp = exp - (op->stats.exp - max_exp);
  1438.     op->stats.exp=max_exp;
  1439.   }     
  1440.   return exp;    /* return the actual amount changed stats.exp by */ 
  1441. }
  1442.  
  1443. /* check_dm_add_exp() - called from c_wiz.c. Needed by ALLOW_SKILLS
  1444.  * code. -b.t.
  1445.  */
  1446.  
  1447. int check_dm_add_exp_to_obj(object *exp_ob, int i) {
  1448.  
  1449.   if((exp_ob->stats.exp + i) < 0) 
  1450.       i= -1*(exp_ob->stats.exp);
  1451.   else if((exp_ob->stats.exp +i)> MAX_EXP_IN_OBJ)
  1452.       i= MAX_EXP_IN_OBJ - exp_ob->stats.exp;
  1453.   return i;
  1454. }
  1455.